/*
   Copyright 2011 Sonja Pieper

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package de.delusions.measure;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.TimePicker;
import de.delusions.measure.activities.prefs.UserPreferences;
import de.delusions.measure.database.MeasureCursorAdapter;
import de.delusions.measure.database.SqliteHelper;
import de.delusions.measure.ment.MeasureType;
import de.delusions.measure.ment.Measurement;
import de.delusions.measure.ment.MeasurementException;

public class MeasureEdit extends Activity {

    public static final String EDIT_TYPE = "type";

    private SqliteHelper mDbHelper;

    private Long mRowId;
    private MeasureType field;
    private EditText input;
    private boolean createMode;
    private int spinnerPosition = 0;
    private Calendar calendar;
    private Button dateButton;
    private Button timeButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_edit);

        this.mDbHelper = new SqliteHelper(this);
        this.mDbHelper.open();
        this.input = (EditText) findViewById(R.id.input);

        // this.timeButton = (Button) findViewById(R.id.timePickerButton);

        retrieveExtras(savedInstanceState);
        setUnitLabel();
        setTitle();
        this.dateButton = (Button) findViewById(R.id.datePickerButton);
        this.dateButton.setOnClickListener(new ShowDialogClickListener(this,
                R.id.datePickerButton));
        this.timeButton = (Button) findViewById(R.id.timePickerButton);
        this.timeButton.setOnClickListener(new ShowDialogClickListener(this,
                R.id.timePickerButton));
        createConfirmButton();
        manageFieldSpinner();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putSerializable(SqliteHelper.KEY_ROWID, this.mRowId);
        outState.putSerializable(EDIT_TYPE, this.field);
    }

    @Override
    protected void onResume() {
        super.onResume();
        populateInput();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        this.mDbHelper.close();
    }

    private void createConfirmButton() {
        final Button confirmButton = (Button) findViewById(R.id.ok);
        confirmButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                setResult(RESULT_OK);
                saveMeasurement();
                finish();
            }
        });
    }

    private void retrieveExtras(Bundle savedInstanceState) {
        this.mRowId = savedInstanceState == null ? null
                : (Long) savedInstanceState
                        .getSerializable(SqliteHelper.KEY_ROWID);
        if (this.mRowId == null) {
            final Bundle extras = getIntent().getExtras();
            this.mRowId = extras != null ? extras
                    .getLong(SqliteHelper.KEY_ROWID) : null;
            Log.d(MeasureActivity.TAG, "retrieveExtras " + this.mRowId);
        }
        this.field = savedInstanceState == null ? null
                : (MeasureType) savedInstanceState.getSerializable(EDIT_TYPE);
        if (this.field == null) {
            final Bundle extras = getIntent().getExtras();
            this.field = extras != null ? (MeasureType) extras
                    .getSerializable(EDIT_TYPE) : null;
            Log.d(MeasureActivity.TAG, "retrieveExtras " + this.field);
        }
        this.createMode = this.mRowId == -1;
    }

    private void setTitle() {
        if (this.createMode) {
            setTitle(getResources().getString(R.string.activity_createmeasure));
        } else {
            final String label = this.field == null ? null : this.field
                    .getLabel(this);
            setTitle(getResources().getString(R.string.activity_editmeasure)
                    + " " + label);
        }
    }

    private void populateInput() {
        Log.d("populateInput", "Populating input...");

        initDateTimeCheckBox((CheckBox) findViewById(R.id.dateEditCheckBox));

        if (this.createMode) {
            Log.d("populateInput", "In createMode");

            // Set the date and time to current
            this.calendar = Calendar.getInstance();
            this.dateButton.setText(MeasureCursorAdapter.DATE_FORMAT
                    .format(this.calendar.getTime()));
            this.timeButton.setText(MeasureCursorAdapter.TIME_FORMAT
                    .format(this.calendar.getTime()));

        } else {
            final Cursor cursor = this.mDbHelper.fetchById(this.mRowId);
            if (cursor.getCount() != 0) {
                final Measurement measurement = this.field
                        .createMeasurement(cursor);
                this.input.setText(measurement.prettyPrint(this));

                if (this.calendar == null) {
                    this.calendar = Calendar.getInstance();
                }

                this.calendar.setTime(measurement.getTimestamp());
                this.dateButton.setText(MeasureCursorAdapter.DATE_FORMAT
                        .format(this.calendar.getTime()));
                this.timeButton.setText(MeasureCursorAdapter.TIME_FORMAT
                        .format(this.calendar.getTime()));

            }
            cursor.close();
        }
    }

    private void initDateTimeCheckBox(View dateTimeCheckBox) {
        dateTimeCheckBox.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Log.d("dataEditCheckBox", "Date edit checkbox clicked");
                Button dateButton = (Button) findViewById(R.id.datePickerButton);
                Button timeButton = (Button) findViewById(R.id.timePickerButton);

                CheckBox checkBox = (CheckBox) v;
                if (checkBox.isChecked()) {
                    dateButton.setVisibility(View.VISIBLE);
                    timeButton.setVisibility(View.VISIBLE);
                } else {
                    dateButton.setVisibility(View.GONE);
                    timeButton.setVisibility(View.GONE);
                }

            }
        });
    }

    public void setUnitLabel() {
        final TextView unit = (TextView) findViewById(R.id.unit);
        unit.setText(this.field.getUnit().retrieveUnitName(this));
    }

    private void saveMeasurement() {
        final String strValue = this.input.getText().toString();
        final Date date = this.calendar.getTime();
        Log.d("saveMeasurement", "Saving date: "
                + MeasureCursorAdapter.DATE_FORMAT.format(date) + " "
                + MeasureCursorAdapter.TIME_FORMAT.format(date));

        try {
            final Measurement measurement = new Measurement(null, strValue,
                    this.field, UserPreferences.isMetric(this), date);

            measurement.setField(this.field);

            if (this.createMode) {
                final long id = this.mDbHelper.createMeasure(measurement);
                if (id > 0) { // TODO may not be needed
                    this.mRowId = id;
                }
            } else {
                this.mDbHelper.updateMeasure(this.mRowId, measurement);
            }

        } catch (final MeasurementException e) {
            String s = getResources().getText(R.string.error_write_db)
                    .toString();
            e.createToast(MeasureEdit.this, s);
        }
    }

    public void manageFieldSpinner() {
        final Spinner spinner = (Spinner) findViewById(R.id.chooseType);
        if (this.createMode) {
            spinnerFill(spinner);
        } else {
            spinner.setVisibility(View.GONE);
        }
    }

    protected void spinnerFill(final Spinner spinner) {
        final List<MeasureType> types = MeasureType.getEnabledTypes(this);
        final List<String> spinnerLabels = createLabels(types);
        Log.d(MeasureActivity.TAG, "spinnerFill in edit " + spinnerLabels);
        final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_spinner_item, spinnerLabels);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);
        spinner.setSelection(this.spinnerPosition);
        spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view,
                    int pos, long id) {
                MeasureEdit.this.field = types.get(pos);
                setUnitLabel();
                UserPreferences.setDisplayField(MeasureEdit.this,
                        MeasureEdit.this.field);
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                // Do nothing.
            }
        });
    }

    protected int getSpinnerPosition() {
        return this.spinnerPosition;
    }

    Calendar getCalendar() {
        return this.calendar;
    }

    protected List<String> createLabels(final List<MeasureType> types) {
        final List<String> spinnerLabels = new ArrayList<String>();
        this.spinnerPosition = 0;
        boolean found = false;
        for (final MeasureType field : types) {
            spinnerLabels.add(getResources().getString(field.getLabelId()));
            found = found || field.equals(MeasureEdit.this.field);
            if (!found) {
                this.spinnerPosition++;
            }
        }
        return spinnerLabels;
    }

    // updates the date in the TextView
    private void updateDisplay(Calendar calendar) {
        Date d = calendar.getTime();
        this.dateButton.setText(MeasureCursorAdapter.DATE_FORMAT.format(d));
        this.timeButton.setText(MeasureCursorAdapter.TIME_FORMAT.format(d));
    }

    /** The callback received when the user "sets" the date in the dialog. */
    private DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener() {

        @Override
        public void onDateSet(DatePicker view, int year, int month, int day) {
            // Get the current date so we can preserve the time
            Calendar c = getCalendar();
            c.set(year, month, day);
            updateDisplay(c);
        }
    };

    /** The callback received when the user "sets" the time in the dialog. */
    private TimePickerDialog.OnTimeSetListener timeSetListener = new TimePickerDialog.OnTimeSetListener() {

        @Override
        public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
            Calendar c = getCalendar();
            c.set(Calendar.HOUR_OF_DAY, hourOfDay);
            c.set(Calendar.MINUTE, minute);
            updateDisplay(c);
        }
    };

    // TODO: android.app.Activity.onCreateDialog is deprecated
    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case R.id.datePickerButton:
            return new DatePickerDialog(this, mDateSetListener,
                    this.calendar.get(Calendar.YEAR),
                    this.calendar.get(Calendar.MONTH),
                    this.calendar.get(Calendar.DAY_OF_MONTH));
        case R.id.timePickerButton:
            return new TimePickerDialog(this, timeSetListener,
                    this.calendar.get(Calendar.HOUR_OF_DAY),
                    this.calendar.get(Calendar.MINUTE), true);
        }
        return null;
    }
}
